//
// Copyright (c) 2019-2023 BPer
//

#include <bperstream/BPerSynBufferManager.h>
#include <bperutil/buffer/BPerAudioPlayBuffer.h>


bPer_vector_impl2(BPerSynBuffer)

int32_t bPer_synBufMan_getAudioDatas(BPerSynBufferSession* session, uint8_t* mixBuf,BPerFrame* pframe){
	if(session==NULL || pframe==NULL) return 1;

	if(session->playBuffers==NULL) return 1;
	uint8_t *tmp = NULL;
	int32_t count=0;
	bPer_thread_mutex_lock(&session->playBufferMutex);
	BPerSynBuffer* syn;
	for (int32_t i = 0; i < session->playBuffers->vec.vsize; i++) {
		syn=session->playBuffers->vec.payload[i];
		if (syn && syn->getAudioSize(syn->session) > 0) {
			tmp = syn->getAudioRef(syn->session,pframe);

			if (tmp) {
				// if (m_preProcess)	m_preProcess->preprocess_run((short*) tmp);
				if (count == 0) {
					bPer_memcpy(mixBuf, tmp, pframe->nb);
				} else {
					bPer_mixaudio_mix1((short*)mixBuf, (short*)tmp, pframe->nb, 128);
				}
				count++;
			}
			tmp = NULL;

			// if (m_in_audioBuffer->at(i)->size() > m_audioPlayCacheNum)                m_in_audioBuffer->at(i)->resetIndex();
		}
	}
	bPer_thread_mutex_unlock(&session->playBufferMutex);


	return count>0?BPer_Ok:1;
}

int32_t bPer_synBufMan_getPlayBufferIndex(BPerSynBufferSession* session,int puid){
	if(session==NULL) return -1;

	if(session->playBuffers){
		for(int32_t i=0;i<session->playBuffers->vec.vsize;i++){
			if(session->playBuffers->vec.payload[i]->getUid(session->playBuffers->vec.payload[i]->session)==puid) return i;
		}
	}
	return -1;
}


int32_t bPer_synBufMan_addAudioBuffer(BPerSynBufferSession* session,void* BPerAudioPlay,int32_t puid){
	if(session==NULL) return 1;
	BPerAudioPlayBuffer* audioPlayBuf=(BPerAudioPlayBuffer*)BPerAudioPlay;
	int ind=bPer_synBufMan_getPlayBufferIndex(session,puid);
	if(ind==-1){
		BPerSynBuffer* syn=(BPerSynBuffer*)bPer_calloc(sizeof(BPerSynBuffer),1);//new BPerSynBuffer();
		syn->setUid(syn->session,puid);
		syn->setInAudioBuffer(syn->session,audioPlayBuf);
		bPer_thread_mutex_lock(&session->playBufferMutex);
		if(session->playBuffers) session->playBuffers->insert(&session->playBuffers->vec,syn);
		bPer_thread_mutex_unlock(&session->playBufferMutex);
		return BPer_Ok;
	}
	return 1;
}

void bPer_synBufMan_initAudioBuffer(BPerSynBufferSession* session){
	if(session==NULL||session->playBuffers!=NULL) return;
	session->playBuffers=(BPerSynBufferVector2*)bPer_calloc(sizeof(BPerSynBufferVector2),1);
	bPer_create_BPerSynBufferVector2(session->playBuffers);
}

void bPer_synBufMan_removeAllAudioBuffer(BPerSynBufferSession* session){
	if(session==NULL) return ;
	bPer_thread_mutex_lock(&session->playBufferMutex);
	if(session->playBuffers){
		for(int32_t i=0;i<session->playBuffers->vec.vsize;i++){
			bPer_free(session->playBuffers->vec.payload[i]);
		}
		session->playBuffers->clear(&session->playBuffers->vec);
	}
	bPer_thread_mutex_unlock(&session->playBufferMutex);
}

BPerSynBuffer* bPer_synBufMan_getSynBuffer(BPerSynBufferSession* session,int puid){
	if(session==NULL) return NULL;
	int ind=bPer_synBufMan_getPlayBufferIndex(session,puid);
	if(ind==-1) return NULL;
	return session->playBuffers->vec.payload[ind];
}

void bPer_synBufMan_removeAudioBuffer(BPerSynBufferSession* session,int32_t puid){
	if(session==NULL) return ;
	bPer_thread_mutex_lock(&session->playBufferMutex);
	int ind=bPer_synBufMan_getPlayBufferIndex(session,puid);
	if(session->playBuffers&&ind>-1){
		bPer_destroy_synBuffer(session->playBuffers->vec.payload[ind]);
		bPer_free(session->playBuffers->vec.payload[ind]);
		session->playBuffers->remove(&session->playBuffers->vec, ind);
	}
	bPer_thread_mutex_unlock(&session->playBufferMutex);

}


void bPer_create_synBufferManager(BPerSynBufferManager* man){
	if(man==NULL) return;
	BPerSynBufferSession* session=(BPerSynBufferSession*)bPer_calloc(sizeof(BPerSynBufferSession),1);
	man->session=session;
	bPer_thread_mutex_init(&session->playBufferMutex,NULL);

	man->getSynBuffer=bPer_synBufMan_getSynBuffer;
	man->getPlayBufferIndex=bPer_synBufMan_getPlayBufferIndex;
	man->getAudioDatas=bPer_synBufMan_getAudioDatas;
	man->addAudioBuffer=bPer_synBufMan_addAudioBuffer;
	man->initAudioBuffer = bPer_synBufMan_initAudioBuffer;
	man->removeAllAudioBuffer=bPer_synBufMan_removeAllAudioBuffer;
	man->removeAudioBuffer=bPer_synBufMan_removeAudioBuffer;

}

void bPer_destroy_synBufferManager(BPerSynBufferManager* man){
	if(man==NULL||man->session==NULL) return;
	BPerSynBufferSession* session=(BPerSynBufferSession*)man->session;
	bPer_free(session->playBuffer);
	if(session->playBuffers){
		for(int32_t i=0;i<session->playBuffers->vec.vsize;i++){
			bPer_destroy_synBuffer(session->playBuffers->vec.payload[i]);
			bPer_free(session->playBuffers->vec.payload[i]);
		}
		session->playBuffers->clear(&session->playBuffers->vec);
		bPer_destroy_BPerSynBufferVector2(session->playBuffers);
		bPer_free(session->playBuffers);
	}

	bPer_thread_mutex_destroy(&session->playBufferMutex);
}
